gofr <- function(d, dr = .01) {
    # Get a vector of all Euclidian distances
    dd <- as.vector(dist(d))
    # Make a histogram out of it
    dd.hist <- hist(dd,
        breaks = seq(0, max(dd) + dr, by = dr),
        plot = FALSE
    )
    # Get the r values
    r <- dd.hist$mids
    # Compute the normalization by the bin surface
    rlo <- r - dr / 2
    rup <- r + dr / 2
    nideal <- pi * (rup^2 - rlo^2)
    # Return the tibble containing r and G(r)
    tibble::tibble(
        r = r,
        gofr = dd.hist$counts / nideal
    )
}
# Example of use
ddr <- 1
d <- tibble(
    x = rep(seq(0, 10, ddr), 10 / ddr + 1),
    y = rep(seq(0, 10, ddr), each = 10 / ddr + 1)
)
ggplot(d, aes(x, y)) +
    geom_point()

G <- gofr(d, dr = .05)
library(plotly)
P <- ggplot(G, aes(x = r, y = gofr)) +
    geom_line()
ggplotly(P)
LS0tCnRpdGxlIDogIlIgRXhlcmNpc2VzIC0gRyhyKSIKIyB0aXRsZSA6ICJSIEV4ZXJjaXNlcyAtIFNvbHV0aW9uIgpkYXRlICA6ICIyMDIwLTA3LTA5IgpvdXRwdXQ6IAogICAgaHRtbF9kb2N1bWVudDoKICAgICAgICB0b2MgICAgICAgICAgICA6IHRydWUKICAgICAgICB0b2NfZmxvYXQgICAgICA6IHRydWUKICAgICAgICB0b2NfZGVwdGggICAgICA6IDQKICAgICAgICBoaWdobGlnaHQgICAgICA6IHRhbmdvCiAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICAgICAgY29kZV9kb3dubG9hZCAgOiB0cnVlCnBhcmFtczogCiAgICBzb2x1dGlvbjoKICAgICAgICB2YWx1ZTogdHJ1ZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlPUZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKYGBgCgpgYGB7ciBpbmNsdWRlPXBhcmFtcyRzb2x1dGlvbiwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjYWNoZT1GQUxTRX0KZ29mciA8LSBmdW5jdGlvbihkLCBkciA9IC4wMSkgewogICAgIyBHZXQgYSB2ZWN0b3Igb2YgYWxsIEV1Y2xpZGlhbiBkaXN0YW5jZXMKICAgIGRkIDwtIGFzLnZlY3RvcihkaXN0KGQpKQogICAgIyBNYWtlIGEgaGlzdG9ncmFtIG91dCBvZiBpdAogICAgZGQuaGlzdCA8LSBoaXN0KGRkLAogICAgICAgIGJyZWFrcyA9IHNlcSgwLCBtYXgoZGQpICsgZHIsIGJ5ID0gZHIpLAogICAgICAgIHBsb3QgPSBGQUxTRQogICAgKQogICAgIyBHZXQgdGhlIHIgdmFsdWVzCiAgICByIDwtIGRkLmhpc3QkbWlkcwogICAgIyBDb21wdXRlIHRoZSBub3JtYWxpemF0aW9uIGJ5IHRoZSBiaW4gc3VyZmFjZQogICAgcmxvIDwtIHIgLSBkciAvIDIKICAgIHJ1cCA8LSByICsgZHIgLyAyCiAgICBuaWRlYWwgPC0gcGkgKiAocnVwXjIgLSBybG9eMikKICAgICMgUmV0dXJuIHRoZSB0aWJibGUgY29udGFpbmluZyByIGFuZCBHKHIpCiAgICB0aWJibGU6OnRpYmJsZSgKICAgICAgICByID0gciwKICAgICAgICBnb2ZyID0gZGQuaGlzdCRjb3VudHMgLyBuaWRlYWwKICAgICkKfQojIEV4YW1wbGUgb2YgdXNlCmRkciA8LSAxCmQgPC0gdGliYmxlKAogICAgeCA9IHJlcChzZXEoMCwgMTAsIGRkciksIDEwIC8gZGRyICsgMSksCiAgICB5ID0gcmVwKHNlcSgwLCAxMCwgZGRyKSwgZWFjaCA9IDEwIC8gZGRyICsgMSkKKQpnZ3Bsb3QoZCwgYWVzKHgsIHkpKSArCiAgICBnZW9tX3BvaW50KCkKRyA8LSBnb2ZyKGQsIGRyID0gLjA1KQpsaWJyYXJ5KHBsb3RseSkKUCA8LSBnZ3Bsb3QoRywgYWVzKHggPSByLCB5ID0gZ29mcikpICsKICAgIGdlb21fbGluZSgpCmdncGxvdGx5KFApCmBgYAoKCgoKCgoKCgoK